/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package czStvDpds.graphics3D.gui;

import czStvDpds.graphics3D.GraphicsIndex;
import czStvDpds.input.LWJGLKeyEvent;
import czStvDpds.input.LWJGLKeyListener;
import czStvDpds.input.LWJGLMouseEvent;
import czStvDpds.input.LWJGLMouseListener;
import org.lwjgl.input.Mouse;
import org.newdawn.slick.UnicodeFont;

/**
 * Zakladni trida pro komponent grafickeho uzivatelskeho rozhrani. Sama o sobe
 * nefunguje, nepouzivat.
 *
 * @author Ondra
 */
public abstract class LComponent implements LWJGLMouseListener, LWJGLKeyListener {

    protected ComponentLocation loc;
    protected boolean mouseOver;
    protected boolean visible;
    private boolean mouseDown;
    private ComponentPixelSize minSize;
    protected LContainer parent;
    protected GUIObject model;
    public static final UnicodeFont defaultFont = Modeler.getDefaultFont();
    protected UnicodeFont font = LComponent.defaultFont;
    /**
     * udava okraj komponenty
     */
    protected int offset;

    public LComponent() {
        this.loc = new ComponentLocation(0, 0, 0, 0);
        this.minSize = new ComponentPixelSize(0, 0);
        mouseOver = false;
        checkMouseOver();
        this.visible = true;
        GraphicsIndex.getInputHandler().addLWJGLMouseListener(this);
        GraphicsIndex.getInputHandler().addLWJGLKeyListener(this);
        offset = 3;
    }

    /**
     * Metoda, ktera vykresluje component, pokud je viditelny
     */
    public void remodel() {
        model();
    }

    /**
     * zjisti jestli nad komponentou je mys (to ovlivnuje zobrazeni nekterych
     * komponent)
     *
     * @return
     */
    public boolean isMouseOver() {
        return mouseOver;
    }

    /**
     * zjistuje, zda se komponenta vykresluje
     *
     * @return
     */
    public boolean isVisible() {
        return visible;
    }

    /**
     * nastavuje, jestli se bude komponenta zobrazovat.
     *
     * @param visible
     */
    public void setVisible(boolean visible) {
        this.visible = visible;
        model.setEnabled(visible);
        model.setDrawer(SuperContainer.getActiveScene());
//        if (!visible) {
//            SuperContainer.getActiveScene().removeObject(model);
//        }
    }

    /**
     * metoda kresli (3D modeluje) komponent. Bude prepsana u kazdeho typu
     * komponenty jinak
     */
    protected abstract void model();

    @Override
    public void mouseAction(LWJGLMouseEvent e) {
        checkMouseOver();
        if (!mouseDown) {
            mouseDown = Mouse.isButtonDown(0);
            if (mouseDown) {
                if (mouseOver) {
                    mousePressed();
                } else {
                    mousePressedNotHere();
                }

            }
        } else {
            mouseDown = Mouse.isButtonDown(0);
            if (!mouseDown) {
                if (mouseOver) {
                    mouseReleased();
                }
            }
        }
    }

    @Override
    public void keyAction(LWJGLKeyEvent e) {
        if (e.getState()) {
            keyPressed(e);
        }
    }

    /**
     * zjisti, jestli je mys nad komponentou
     *
     * @return
     */
    private void checkMouseOver() {
        int mouseX = Mouse.getX();
        int mouseY = SuperContainer.getActiveScene().getHeight() - Mouse.getY();

        int xPx = Modeler.ratioToPixels(loc.getX());
        int yPx = Modeler.ratioToPixels(loc.getY());
        int heightPx = Modeler.ratioToPixels(loc.getHeight());
        int widthPx = Modeler.ratioToPixels(loc.getWidth());
        boolean result = mouseX >= xPx && mouseX <= (xPx + widthPx) && mouseY >= yPx && mouseY <= (yPx + heightPx);
        if (mouseOver && !result) {
            mouseExited();
        } else if (!mouseOver && result) {
            mouseEntered();
        }
        mouseOver = result;
    }

    /**
     * aby si to potomcci mohli prepsat a neco delat
     */
    protected abstract void mouseExited();

    /**
     * aby si to potomcci mohli prepsat a neco delat
     */
    protected abstract void mouseEntered();

    /**
     * aby si to potomcci mohli prepsat a neco delat
     */
    protected abstract void mousePressed();

    /**
     * aby si to potomcci mohli prepsat a neco delat
     */
    protected abstract void mouseReleased();

    /**
     * aby si to potomci mohli prepsat a neco delat
     *
     * @param charakter
     */
    protected abstract void keyPressed(LWJGLKeyEvent e);

    /**
     * aby si to potomci mohli prepsat a neco delat
     */
    protected abstract void mousePressedNotHere();

    /**
     * vrati container, ve kterem je tenhle komponent ulozeny
     *
     * @return
     */
    public LContainer getParent() {
        return parent;
    }

    public void setParent(LContainer parent) {
        this.parent = parent;
    }

    public ComponentPixelSize getMinSize() {
        return minSize;
    }

    public void setBounds(float x, float y, float width, float height) {
        this.loc.setX(x);
        this.loc.setY(y);
        this.loc.setHeight(height);
        this.loc.setWidth(width);
        remodel();
    }

    /**
     * potomci pomoci ni upravuji svou minimalni velikost. Hlida, aby zadna
     * minSize nebyla vetsi nez 1
     *
     * @param newSize
     */
    protected void setMinSize(ComponentPixelSize newSize) {
        int newWidth = newSize.getWidth() + (2 * offset);
        int newHeight = newSize.getHeight() + (2 * offset);

        float newRelWidth = Math.min(Modeler.pixelsToRatio(newWidth/*
                 * newSize.getWidth()
                 */), SuperContainer.getActiveScene().getUnitRelativeWidth());
        float newRelHeight = Math.min(Modeler.pixelsToRatio(newHeight/*
                 * newSize.getHeight()
                 */), SuperContainer.getActiveScene().getUnitRelativeHeight());
        if (minSize == null) {
            minSize = new ComponentPixelSize(0, 0);
        }
        minSize.setHeight(Modeler.ratioToPixels(newRelHeight));
        minSize.setWidth(Modeler.ratioToPixels(newRelWidth));
    }

    public void setFont(UnicodeFont font) {
        this.font = font;
        this.model.setFont(font);
    }

    public void setOffset(int offset) {
        this.offset = offset;
        recalculateMinSize();
    }

    public int getOffset() {
        return offset;
    }

    /**
     * aby si ji potomci mohli prepsat
     */
    protected abstract void recalculateMinSize();
}
